import json

import matplotlib as mpl
from flask import request
import numpy as np

from app.Controllers.BaseController import BaseController
from app.Package.entity.PowerAnalysisRequestBody import PowerAnalysisRequestBody
from app.Package.power_analysis import power_analysis
from app.Package.power_analysis.plotting import plot_metric_spectrum, plot_metric_curve, plot_metric_heatmap
from app.Service.ChemometricsTutorialsServices.CommonService import getProjectInfo, readDataForPLSR, readDataForPA, \
    getImagePath, getWebImagePath

mpl.use('Agg')
import matplotlib.pyplot as plt


class PowerAnalysisService:

    # 需要进行PowerAnalysis的通用部分，读取项目的信息和表单中的信息用于填入PA类中
    def PACommomProcess(self):
        userId, projectId, data, label, coordinate, savePath = getProjectInfo()
        formdata = request.data.decode('utf-8')
        formjson = json.loads(formdata)
        PA = PowerAnalysisRequestBody(data, label, coordinate, savePath)
        PA.set_data(formjson)
        return PA

    # 解析PowerAnalysis的请求表单,从PA类中获取需要分析的文件名以及用户的存储路径
    def unpackPowerAnalysisRequestBody(self, input_data):
        xfile = input_data.xfile
        yfile = input_data.yfile
        ppmfile = input_data.ppmfile
        thread_path = input_data.thread_path
        ycol = input_data.ycol
        test_label = input_data.test_label
        return xfile, yfile, ppmfile, ycol, test_label, thread_path

    # 获取PowerAnalysis的模型
    def getPowerAnalysisModel(self, xfile, yfile, ppmfile, ycol, test_label, outliers_index=None):
        x, y, ppm = readDataForPA(xfile, yfile, ppmfile, ycol, test_label, outliers_index)
        yn = y[:, ycol]
        return x, y, ppm, yn

    # 进行单个指标的powerAnalysis的CurvePlot（有致命性bug，暂时被废弃）
    def getMetricCurvePlot(self, input_data):
        xfile, yfile, ppmfile, ycol, test_label, thread_path = self.unpackPowerAnalysisRequestBody(input_data)
        x, y, ppm, yn = self.getPowerAnalysisModel(xfile, yfile, ppmfile, ycol, test_label, input_data.outliers_index)
        power_simulation_whole_set = power_analysis(x, input_data.effect_size,
                                                    input_data.sample_size, alpha=input_data.alpha,
                                                    model=input_data.model,
                                                    simmodel=input_data.simmodel,
                                                    fakedata_size=input_data.fakedata_size,
                                                    n_repeats=input_data.n_repeats,
                                                    variables_to_calculate=None)
        fig, ax = plot_metric_curve(power_simulation_whole_set, metric='True Positive Rate',
                                    plot_multiple_testing=False,
                                    fixed_effect_size=None,
                                    fixed_sample_size=np.array([50, 100, 150, 200, 300, 400, 500]), sd=2)
        imageFilename = "MetricCurve"
        imagePath, shortPath = getImagePath(thread_path, imageFilename)
        plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
        webImagePath = getWebImagePath(thread_path, shortPath)
        resultData = {"webImagePath": webImagePath}
        return BaseController().successData(msg='完成分析', data=resultData)

    # 进行单个指标的powerAnalysis的SpectrumPlot
    def getMetricSpectrumPlot(self, input_data):
        xfile, yfile, ppmfile, ycol, test_label, thread_path = self.unpackPowerAnalysisRequestBody(input_data)
        x, y, ppm, yn = self.getPowerAnalysisModel(xfile, yfile, ppmfile, ycol, test_label, input_data.outliers_index)
        power_simulation_whole_set = power_analysis(x, np.array([input_data.effect_size_spectrum]),
                                                    np.array([input_data.sample_size_spectrum]), alpha=input_data.alpha,
                                                    model=input_data.model,
                                                    simmodel=input_data.simmodel,
                                                    fakedata_size=input_data.fakedata_size,
                                                    n_repeats=input_data.n_repeats,
                                                    variables_to_calculate=None)
        fig, ax = plot_metric_spectrum(power_simulation_whole_set, ref_spectrum=np.median(x, axis=0), xvar=np.squeeze(ppm),
                                       plot_multiple_testing=input_data.plot_multiple_testing)
        imageFilename = "MetricSpectrum"
        imagePath, shortPath = getImagePath(thread_path, imageFilename)
        plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
        webImagePath = getWebImagePath(thread_path, shortPath)
        resultData = {"webImagePath": webImagePath}
        return BaseController().successData(msg='完成分析', data=resultData)

    # 进行单个指标的powerAnalysis的HeatmapPlot
    def getHeatmapPlot(self, input_data):
        xfile, yfile, ppmfile, ycol, test_label, thread_path = self.unpackPowerAnalysisRequestBody(input_data)
        x, y, ppm, yn = self.getPowerAnalysisModel(xfile, yfile, ppmfile, ycol, test_label, input_data.outliers_index)
        power_simulation = power_analysis(x, input_data.effect_size,
                                                    input_data.sample_size, alpha=input_data.alpha,
                                                    model=input_data.model,
                                                    simmodel=input_data.simmodel,
                                                    fakedata_size=input_data.fakedata_size,
                                                    n_repeats=input_data.n_repeats,
                                                    variables_to_calculate=None)
        fig, ax = plot_metric_heatmap(power_simulation, which_var=0,
                    interpolation='None', metric="True Positive Rate", contour_level=0.8,
                    plot_multiple_testing=input_data.plot_multiple_testing)
        imageFilename = "HeatmapPlot.png"
        imagePath, shortPath = getImagePath(thread_path, imageFilename)
        plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
        webImagePath = getWebImagePath(thread_path, shortPath)
        resultData = {"webImagePath": webImagePath}
        return BaseController().successData(msg='完成分析', data=resultData)

    # 进行指定指标的powerAnalysis的HeatmapPlot
    def getHeatmapPlotForSignal(self, input_data):
        xfile, yfile, ppmfile, ycol, test_label, thread_path = self.unpackPowerAnalysisRequestBody(input_data)
        x, y, ppm, yn = self.getPowerAnalysisModel(xfile, yfile, ppmfile, ycol, test_label, input_data.outliers_index)
        ppm = np.squeeze(ppm)
        if (input_data.signalValue != None):
            which_var = np.array(np.where(ppm == float(input_data.signalValue))[0])
        else:
            which_var = None
        power_simulation = power_analysis(x, input_data.effect_size,
                                                    input_data.sample_size, alpha=input_data.alpha,
                                                    model=input_data.model,
                                                    simmodel=input_data.simmodel,
                                                    fakedata_size=input_data.fakedata_size,
                                                    n_repeats=input_data.n_repeats,
                                                    variables_to_calculate=which_var)
        fig, ax = plot_metric_heatmap(power_simulation, which_var=0,
                    interpolation='None', metric="True Positive Rate", contour_level=0.8,
                    plot_multiple_testing=input_data.plot_multiple_testing)
        imageFilename = "HeatmapPlot.png"
        imagePath, shortPath = getImagePath(thread_path, imageFilename)
        plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
        webImagePath = getWebImagePath(thread_path, shortPath)
        resultData = {"webImagePath": webImagePath}
        return BaseController().successData(msg='完成分析', data=resultData)
